﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PhoneApplicPersons.Interfaces;
using PhoneApplicPersons.Classes;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace PhoneApplicPersons.DS
{
    public class DS_NET_CLIENT : IDS
    {
        static ManualResetEvent clientDoneEvent = new ManualResetEvent(false);
        const int timeout = 5000;
        const int maxBufferSize = 2048;
        Socket sender = null;
        private string path = "127.0.0.1:8001";
        public string Path { set { path = value; } }
        private IDS next = null;
        public IDS Next { set { next = value; } }
        public DS_NET_CLIENT() { }
        public DS_NET_CLIENT(string _path) { Path = _path; }
        public IDS isReady(string _ext, string _path)
        {
            IDS ret = null;
            if ("net" == _ext) { ret = this; ret.Path = _path; }
            else if (next != null) { ret = next.isReady(_ext, _path); }
            return ret;
        }

        public void Create(Persona p)
        {
            try
            {

                string message = "insert" + "_" + Persona.MakeCSVStrFromPersona(p);
                connect(message);
            }
            catch (Exception ex)
            {
                throw new SystemException(ex.Message);
            }
        }
        public List<Persona> Read()
        {
            try
            {
                List<Persona> rez = new List<Persona>();
                string message = "read" + "_" + " ";
                connect(message);
                message = getAnswer();
                //MainPage.listAsString = message;
                string[] split = message.Split(';', '_');
                for (int i = 0; i < split.Length - 1; i++)
                {
                    rez.Add(Persona.GetPersonaFromCSVStr(split[i]));
                }
                //Socket Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //string[] split = path.Split(new Char[] { ':' });
                //Client.Connect(IPAddress.Parse(split[0]), Convert.ToInt32(split[1]));
                //Client.Send(Encoding.ASCII.GetBytes("read" + ";" + " "));
                //byte[] bytes = new byte[Client.Available];
                //if (Client.Available > 0)
                //{
                //    int BytesRes = Client.Receive(bytes);
                //    string data = Encoding.ASCII.GetString(bytes, 0, BytesRes);
                //    split = data.Split(new Char[] { ';' });
                //    if (split[0] == "error")
                //    {
                //        throw new SystemException(split[1]);
                //    }
                //    else
                //    {
                //        for (int i = 0; i < split.Length - 1; i++)
                //        {
                //            rez.Add(Persona.GetPersonaFromCSVStr(split[i]));
                //        }
                //    }
                //}
                //Client.Close();
                return rez;
            }
            catch (Exception ex)
            {
                throw new SystemException(ex.Message);
            }
        }

        public List<Persona> Read(int ID)
        {
            try
            {
                List<Persona> rez = new List<Persona>();
                string message = "readid" + "_" + " ";
                connect(message);
                message = getAnswer();
                //MainPage.listAsString = message;
                string[] split = message.Split(';', '_');
                for (int i = 0; i < split.Length - 1; i++)
                {
                    rez.Add(Persona.GetPersonaFromCSVStr(split[i]));
                }
                //Socket Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //string[] split = path.Split(new Char[] { ':' });
                //Client.Connect(IPAddress.Parse(split[0]), Convert.ToInt32(split[1]));
                //Client.Send(Encoding.ASCII.GetBytes("readid" + ";" + ID.ToString()));
                //byte[] bytes = new byte[Client.Available];
                //int BytesRes = Client.Receive(bytes);
                //string data = Encoding.ASCII.GetString(bytes, 0, BytesRes);
                //split = data.Split(new Char[] { ';' });
                //if (split[0] == "error")
                //{
                //    throw new SystemException(split[1]);
                //}
                //else
                //{
                //    for (int i = 0; i < split.Length - 1; i++)
                //    {
                //        rez.Add(Persona.GetPersonaFromCSVStr(split[i]));
                //    }
                //}

                //Client.Close();
                return rez;
            }
            catch (Exception ex)
            {
                throw new SystemException(ex.Message);
            }
        }

        public void Update(Persona p)
        {
            try
            {
                string message = "update" + "_" + Persona.MakeCSVStrFromPersona(p);
                connect(message);
                //    Socket Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //    string[] split = path.Split(new Char[] { ':' });
                //    Client.Connect(IPAddress.Parse(split[0]), Convert.ToInt32(split[1]));
                //    Client.Send(Encoding.ASCII.GetBytes("update" + ";" + Persona.MakeCSVStrFromPersona(p)));
                //    if (Client.Available > 0)
                //    {
                //        byte[] bytes = new byte[Client.Available];
                //        int BytesRes = Client.Receive(bytes);
                //        string data = Encoding.ASCII.GetString(bytes, 0, BytesRes);
                //        split = data.Split(new Char[] { ';' });
                //        if (split[0] == "error")
                //        {
                //            throw new SystemException(split[1]);
                //        }
                //        Client.Close();
                //    }
            }
            catch (Exception ex)
            {
                throw new SystemException(ex.Message);
            }
        }

        public void Delete(int ID)
        {
            try
            {
                string message = "delete" + "_" + ID.ToString();
                connect(message);
                //    Socket Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //    string[] split = path.Split(new Char[] { ':' });
                //    Client.Connect(IPAddress.Parse(split[0]), Convert.ToInt32(split[1]));
                //    Client.Send(Encoding.ASCII.GetBytes("delete" + ";" + ID.ToString()));
                //    if (Client.Available > 0)
                //    {
                //        byte[] bytes = new byte[Client.Available];
                //        int BytesRes = Client.Receive(bytes);
                //        string data = Encoding.ASCII.GetString(bytes, 0, BytesRes);
                //        split = data.Split(new Char[] { ';' });
                //        if (split[0] == "error")
                //        {
                //            throw new SystemException(split[1]);
                //        }
                //        Client.Close();
                //    }
            }
            catch (Exception ex)
            {
                throw new SystemException(ex.Message);
            }
        }
        void connect(string messageToSend)
        {
            sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            string result;
            byte[] msg = Encoding.UTF8.GetBytes(messageToSend);

            DnsEndPoint hostEntry = new DnsEndPoint("Amigo-UA", 8001);
            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
            socketEventArg.RemoteEndPoint = hostEntry;

            socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
            {
                result = e.SocketError.ToString();
                clientDoneEvent.Set();
            });

            clientDoneEvent.Reset();

            sender.ConnectAsync(socketEventArg);

            clientDoneEvent.WaitOne(timeout);

            ///
            ///

            socketEventArg = new SocketAsyncEventArgs();

            socketEventArg.RemoteEndPoint = sender.RemoteEndPoint;
            socketEventArg.UserToken = null;

            socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
            {
                result = e.SocketError.ToString();

                clientDoneEvent.Set();
            });

            socketEventArg.SetBuffer(msg, 0, msg.Length);

            clientDoneEvent.Reset();

            sender.SendAsync(socketEventArg);

            clientDoneEvent.WaitOne(timeout);

            //sender.Close();
        }

        string getAnswer()
        {
            string response = "Operation Timeout";

            if (sender != null)
            {
                SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();

                socketEventArg.SetBuffer(new Byte[maxBufferSize], 0, maxBufferSize);

                socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
                {
                    if (e.SocketError == SocketError.Success)
                    {
                        response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
                        response = response.Trim('\0');
                    }
                    else
                    {
                        response = e.SocketError.ToString();
                    }

                    clientDoneEvent.Set();
                });
                clientDoneEvent.Reset();

                sender.ReceiveAsync(socketEventArg);

                clientDoneEvent.WaitOne(50000);
                if (response == "Operation Timeout" || response == "NotConnected" ||
                    response == "ConnectionReset")
                {
                    getAnswer();
                }
            }
            else
            {
                response = "Socket is not initialized";
            }

            sender.Close();
            return response;
        }
    }
}
